#!/usr/bin/env python
#
#       Objects.py
#       
#       Copyright 2009 Ben Davis <its.hip@gmail.com>, Pete Lord <mr.petelord@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import pygame

import Angles
import Bounce
import Options
import Orders

from Client import Client
client = Client()

class Object():
    def __init__(self, x, y, r):
        self.x = x
        self.y = y
        self.r = Angles.Angle(r)
        # MAKE GAME BETTER NOTE
        #when Objects are created, randomize the offset / self.x_mod_amount values.
        # this way different ships will bob at different times and stuff. Nicer. Less motion sickness.
#        self.x_mod = Bounce.Bouncer(0,0,0,1 )
#        self.y_mod = Bounce.Bouncer(1,1,1,30)
        self.xy_mod = Bounce.BounceXY((0,0,0,1), (1,1,1,30))
        
        self.x_map_mod = 0.0
        self.y_map_mod = 0.0
        
        self.turns = []
        self.orders = Orders.Orders()
        self.queue = []
        self.divisions = 0
        
        self.has_anim = False
        self.anim_frames = 0
        self.anim_frame_times = 20 # 
        self.current_time = 0
        self.current_frame = 0 # init.
            
    def draw(self):
        # the Ship class should _never_ be instantiated, this funcition will not work without self.textures
        # which is defined as part of the ship class itself.
        return self.textures[Options.ZOOM_LEVEL][0][self.r][self.current_frame], pygame.Rect(self.screen_location(), (Options.SPRITE_SIZE[Options.ZOOM_LEVEL], Options.SPRITE_SIZE[Options.ZOOM_LEVEL]))

    def move(self, move):
        self.divisions += 1
        x, y = self.get_relative_tile_direction_relative(0, move, 0)
        self.x_map_mod += float(x) / Options.ANIMATION_DIVISIONS
        self.y_map_mod += float(y) / Options.ANIMATION_DIVISIONS
        if self.divisions == Options.ANIMATION_DIVISIONS:
            self.divisions = 0
            self.x += x
            self.y += y
            self.x_map_mod = 0
            self.y_map_mod = 0
            del self.queue[0]
    
    def rotate(self, r):
        self.r += r
        del self.queue[0]
    
    def poll(self):
        # mostly for x/y_mod magic. off we go!
        # tick timers.
        self.xy_mod.poll()
        
        if self.has_anim:
            self.current_time += 1
            if self.current_time >= self.anim_frame_times:
                self.current_frame += 1
                self.current_time = 0
            if self.current_frame == self.anim_frames:
                self.current_frame = 0
        
        if len(self.orders) > 0:
            self.steam += -self.orders.steam
            self.orders.apply()
            self.turns.append(self.orders)
            self.orders = Orders.Orders()
            if Options.SELECT_WHEN_NO_STEAM:
                if client.game.players.turn == client.game.player.key():
                    ship = client.game.player.ships.first_ship_with_steam()
                    # If player has a ship with steam
                    if ship:
                        client.game.select((ship.x, ship.y))
                        if Options.PAN_ON_SELECT:
                            client.game.pan_to_ship(client.game.selected, 30)
        
        try:
            self.queue[0][0](self.queue[0][1])
            
        except IndexError:
            pass
        
    def pos(self):
        return (self.x, self.y, self.r)
    
    def turn(self, amount):
        self.r += amount
        
    def get_direction_to_tile_2(self, x, y):
        x1 = self.x
        y1 = self.y
        x2 = x
        y2 = y
        value = 0
        if x1 < x2: #left of
            if y1 < y2: # above
                value = 6
            elif y1 > y2: # below
                value = 4
            else: # directly left of
                value = 5
        elif x1 > x2: # right of
            if y1 < y2: # above
                value = 0
            elif y1 > y2: # below
                value = 2
            else: # directly right of of
                value = 1
        else: # equal.
            if y1 < y2: # above
                value = 7
            else: # below
                value = 3
                
        return Angles.Angle(value)
        
    def get_direction_to_tile(self, x, y):
        return self.get_direction_to_tile_relative(x - self.x, y - self.y)

    def get_tile_ahead_x(self, x):
        """THIS. RETURNS. A TILE XY, x tiles ahead of the ship. OK?"""
        return self.get_tile_direction_relative(0, x, 0)
        
    def get_direction_to_tile_relative(self, x, y):
        i = 0
        for pos in (0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1):
            if pos == (x, y):
                return Angles.Angle(i)
            i += 1
    
    def get_direction_relative(self, direction):
        # gets a direction relative to the ships direction. e.g. 2 = right, so this will get you right of the ship.
        return self.r + direction
        
    def get_relative_tile_direction_relative(self, x, y, direction):
        """Returns the tile relative to ship at the direction relative to object"""
        r = self.get_direction_relative(direction)
        if r == 0: # N
            return x, -y
        elif r == 2: # E

            return y, x
        elif r == 4: # S
            return -x, y
        elif r == 6: # W
            return -y, -x
        elif r == 1: # NE
            rx, ry = y + x, -y + x
        elif r == 3: # SE
            rx, ry = y - x, y + x
        elif r == 5: # SW
            rx, ry = -y - x, y - x
        elif r == 7: # NW
            rx, ry = -y + x, -y - x
        if abs(rx) != abs(ry):
            rx = rx / 2
            ry = ry / 2
        return rx, ry
    
    def get_tile_direction_relative(self, x, y, direction):
        x, y = self.get_relative_tile_direction_relative(x, y, direction)
        return self.x + x, self.y + y
        
    def screen_location(self):
        # get the tuple (x, y) of the sprites screen location
        x, y = self.shadow_location()
        x += self.xy_mod.x.value()
        y += self.xy_mod.y.value()
        return (x, y - Options.TILE_HEIGHT[Options.ZOOM_LEVEL])
    
    def shadow_location(self):
        x = (self.x + self.x_map_mod - self.y - self.y_map_mod + client.game.map.height - 1) * 0.5 * Options.TILE_WIDTH[Options.ZOOM_LEVEL]
        y = (self.x + self.x_map_mod + self.y + self.y_map_mod) * 0.5 * Options.TILE_HEIGHT[Options.ZOOM_LEVEL]
        return (x, y)